package com.tanhua.server.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.tanhua.autoconfig.template.HuanXinTemplate;
import com.tanhua.dubbo.api.*;
import com.tanhua.model.domain.Question;
import com.tanhua.model.domain.UserInfo;
import com.tanhua.model.mongo.RecommendUser;
import com.tanhua.model.mongo.UserLike;
import com.tanhua.model.mongo.Visitors;
import com.tanhua.model.mongodto.RecommendUserDto;
import com.tanhua.model.vo.ErrorResult;
import com.tanhua.model.vo.NearUserVo;
import com.tanhua.model.vo.PageResult;
import com.tanhua.model.vo.TodayBest;
import com.tanhua.server.exception.BusinessException;
import com.tanhua.server.interceptor.UserHolder;
import com.tanhua.utils.Constants;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SetOperations;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class TanHuaService {

    @DubboReference
    private UserInfoApi userInfoApi;

    @DubboReference
    private RecommendUserApi recommendUserApi;

    @DubboReference
    private QuestionApi questionApi;

    @Autowired
    private HuanXinTemplate huanXinTemplate;

    @DubboReference
    private UserLikeApi userLikeApi;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @DubboReference
    private UserLocationApi userLocationApi;

    @DubboReference
    private VisitorsApi visitorsApi;

    /**
     * 查询当前用户今日佳人
     *
     * @return
     */
    public TodayBest todayBest() {
        //获取当前用户的id
        Long toUserId = UserHolder.getUserId();
        //调用api查询
        RecommendUser recommendUser = recommendUserApi.findRecommendUser(toUserId);

        if (recommendUser == null) {
            recommendUser = new RecommendUser();
            recommendUser.setUserId(1l);
            recommendUser.setScore(99d);
        }

        UserInfo userInfo = userInfoApi.findById(recommendUser.getUserId());

        TodayBest todayBest = TodayBest.init(userInfo, recommendUser);

        return todayBest;
    }

    /**
     * 推荐朋友
     *
     * @return
     */
    public PageResult recommendation(RecommendUserDto dto) {
        Long userId = UserHolder.getUserId();
        //调用mongoApi查询推荐朋友的id
        PageResult pageResult = recommendUserApi.findRecommendFriend(dto.getPage(), dto.getPagesize(), userId);

        List<RecommendUser> items = (List<RecommendUser>) pageResult.getItems();

        if (items == null || items.size() <= 0) {
            return pageResult;
        }

        List<Long> ids = items.stream().map((item) -> {
            Long userId1 = item.getUserId();

            return userId1;
        }).collect(Collectors.toList());
        UserInfo u = new UserInfo();
        u.setAge(dto.getAge());
        u.setGender(dto.getGender());
        u.setCity(dto.getCity());
        u.setEducation(dto.getEducation());


        Map<Long, UserInfo> map = userInfoApi.findByIds(u, ids);

        //递归循环查询页数是否满足条件的用户信息
        if (CollUtil.isEmpty(map)) {
            dto.setPage(dto.getPage() + 1);
            recommendation(dto);
        }

        List<TodayBest> todayBestList = new ArrayList<>();
        for (RecommendUser item : items) {
            UserInfo userInfo = map.get(item.getUserId());
            if (userInfo != null) {
                TodayBest todayBest = TodayBest.init(userInfo, item);
                todayBestList.add(todayBest);
            }
        }

        pageResult.setItems(todayBestList);

        return pageResult;
    }

    /**
     * 查询佳人详情信息
     *
     * @param personalId
     * @return
     */
    public TodayBest personalInfo(Long personalId) {
        //查询缘分值
        RecommendUser recommendUser = recommendUserApi.findByPersonalId(personalId, UserHolder.getUserId());

        //添加你看过该用的记录并存储到表中
        Visitors visitors = new Visitors();
        visitors.setUserId(recommendUser.getUserId());
        visitors.setVisitorUserId(UserHolder.getUserId());
        visitors.setFrom("首页");
        visitors.setDate(System.currentTimeMillis());
        visitors.setVisitDate(new SimpleDateFormat("yyyyMMdd").format(new Date()));
        visitors.setScore(recommendUser.getScore());
        //调用API存入数据
        visitorsApi.saveOrUpdate(visitors);

        //根据佳人id查询用户详情
        UserInfo userInfo = userInfoApi.findById(personalId);
        return TodayBest.init(userInfo, recommendUser);
    }

    /**
     * 查询陌生人问题
     *
     * @param userId
     * @return
     */
    public String strangerQuestions(Long userId) {
        Question question = questionApi.findById(userId);
        return question == null ? "你喜欢九转大肠吗?" : question.getTxt();
    }

    /**
     * 回复陌生人信息
     *
     * @param userId
     * @param reply
     */
    public void replyQuestions(Integer userId, String reply) {
        Long id = UserHolder.getUserId();
        //调用API查询当前用户的详情信息
        UserInfo userInfo = userInfoApi.findById(id);
        //构造回复数据
        Map map = new HashMap();
        map.put("userId", id);
        map.put("huanXinId", Constants.HX_USER_PREFIX + id);
        map.put("nickname", userInfo.getNickname());
        map.put("strangerQuestion", strangerQuestions(Long.valueOf(userId.toString())));
        map.put("reply", reply);
        String replyQuestions = JSON.toJSONString(map);

        Boolean sendMsg = huanXinTemplate.sendMsg(Constants.HX_USER_PREFIX + userId, replyQuestions);
        if (!sendMsg) {
            throw new BusinessException(ErrorResult.error());
        }
    }

    @Value("${tanhua.default.recommend.users}")
    private String recommendUser;

    /**
     * 推荐列表查询
     *
     * @return
     */
    public List<TodayBest> cards() {
        //调用Api查询推荐列表并排除已经喜欢的和不喜欢的用户id
        List<RecommendUser> recommendUserList = recommendUserApi.findCards(UserHolder.getUserId(), 10);
        //获取筛选后的推荐用户的id
        if (CollUtil.isEmpty(recommendUserList)) {
            //如果没有推荐用户则设置默认用推荐户
            String[] recommendIds = recommendUser.split(",");
            recommendUserList = new ArrayList<>();
            for (String recommendId : recommendIds) {
                RecommendUser recommendUser = new RecommendUser();
                recommendUser.setToUserId(UserHolder.getUserId());
                recommendUser.setUserId(Long.valueOf(recommendId));
                recommendUser.setScore(RandomUtil.randomDouble(60, 90));
                recommendUserList.add(recommendUser);
            }
        }
        //获取推荐用户的id查询用户详情
        List<Long> recommendId = CollUtil.getFieldValues(recommendUserList, "userId", Long.class);
        Map<Long, UserInfo> map = userInfoApi.findByIds(null, recommendId);
        //构造vo对象并返回
        List<TodayBest> list = new ArrayList<>();
        for (RecommendUser recommendUser : recommendUserList) {
            UserInfo userInfo = map.get(recommendUser.getUserId());
            if (userInfo != null) {
                TodayBest vo = TodayBest.init(userInfo, recommendUser);
                list.add(vo);
            }
        }
        return list;
    }

    @Autowired
    private MessagesService messagesService;

    /**
     * 探花-喜欢
     *
     * @param likeId
     */
    public void like(Long likeId) {
        Long userId = UserHolder.getUserId();
        //1. 调用dubbo服务保存数据到MongoDB
        Boolean flag = userLikeApi.saveOrUpdate(userId, likeId, true);
        if (!flag) {
            throw new BusinessException(ErrorResult.error());
        }
        //2. 保存喜欢数据到redis , 删除不喜欢数据
        redisTemplate.opsForSet().add(Constants.USER_LIKE_KEY + userId, likeId.toString());
        redisTemplate.opsForSet().remove(Constants.USER_NOT_LIKE_KEY + userId, likeId.toString());
        //3. 判断是否是双向喜欢, 如果是双向喜欢自动成为好友
        if (isLike(userId, likeId)) {
            messagesService.contacts(Math.toIntExact(likeId));
        }
    }

    //判断是否为双向喜欢
    public boolean isLike(Long userId, Long likeId) {
        return redisTemplate.opsForSet().isMember(Constants.USER_LIKE_KEY + likeId, userId.toString());
    }

    /**
     * 探花-不喜欢
     * @param unlikeUserId
     */
    public void unlike(Long unlikeUserId) {
        Long userId = UserHolder.getUserId();
        //1. 调用dubbo服务保存数据到MongoDB
        Boolean flag = userLikeApi.saveOrUpdate(userId, unlikeUserId, false);
        if (!flag){
            throw  new BusinessException(ErrorResult.error());
        }
        //2.保存不喜欢用户到redis中,并删除喜欢的数据
        redisTemplate.opsForSet().add(Constants.USER_NOT_LIKE_KEY+userId,unlikeUserId.toString());
        Boolean member = redisTemplate.opsForSet().isMember(Constants.USER_LIKE_KEY + userId, unlikeUserId.toString());
        if (member){
            //当前用户之前喜欢了该用户则删除redis中喜欢的数据
            redisTemplate.opsForSet().remove(Constants.USER_LIKE_KEY + userId, unlikeUserId.toString());
            //判断是否互相喜欢,如果互相喜欢解除通信关系
            if (isLike(userId,unlikeUserId)){
                messagesService.deleteContacts(unlikeUserId);
            }
        }
    }

    /**
     * 搜索附近的人
     * @param gender
     * @param distance
     * @return
     */
    public List<NearUserVo> searchUser(String gender, String distance) {
        Long userId = UserHolder.getUserId();
        //调用API获取该用户附近用户的id
        List<Long> searchUserIds = userLocationApi.findSearchUser(userId,distance);
        //searchUserIds.remove(userId);
        //调用API获取用户详情信息
        UserInfo info = new UserInfo();
        info.setGender(gender);
        Map<Long, UserInfo> map = userInfoApi.findByIds(info, searchUserIds);
        //删除用户自己的id
        map.remove(userId);
        List<NearUserVo> vos = new ArrayList<>();
        for (Long id : searchUserIds) {
            UserInfo userInfo = map.get(id);
            if (userInfo != null){
                NearUserVo vo = NearUserVo.init(userInfo);
                vos.add(vo);
            }
        }
        return vos;
    }
}
